package com.lt.flashcard.view;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.zkoss.bind.BindUtils;
import org.zkoss.xel.fn.StringFns;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Path;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.A;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Textbox;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.Flashcard;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Tag;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.FlashcardService;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.Repository;

public class V_wordlistdetail_list extends SelectorComposer<Component> {

    private static final long serialVersionUID = 1L;
    private FlashcardSet flashcardset;
    private WordlistDetailMainCtrl ctrl;
    private boolean canEdit = false;
    private boolean isAdmin = true;
    private boolean buy = false;

    @Wire
    /**
     * The listbox that displays flashcards list
     */
    private Listbox lListboxFlashcard;

    @Wire(".lchkFlashcards")
    private List<Checkbox> lchkFlashcards;
    @Wire
    Textbox fTerm;
    @Wire
    Textbox fNotes;
    @Wire
    Textbox fDefinition;
    @Wire
    Image fImage;
    @Wire
    Label flashcard_name;
    @Wire(".flashcard_term")
    Label flashcard_term;
    @Wire
    Label flashcard_tags;
    @Wire
    Label flashcard_notes;
    @Wire
    Label flashcard_definition;
    @Wire
    Label flashcard_category;
    @Wire
    Label flashcard_wordtype;
    @Wire
    Label flashcard_phonetic;
    @Wire
    Label flashcard_symnonym;
    @Wire
    Image flashcard_img;
    @Wire
    Textbox soundFront;
    @Wire
    Textbox soundBack;
    @Wire
    A l_list;
    @Wire
    A l_grid;
    @Wire
    Textbox g_name_set;
    @Wire
    Textbox description_set;
    @Wire
    Textbox tags_set;
    @Wire
    Listbox g_list_set;

    // detail card
    @Wire
    Label cardid;
    @Wire
    Label carddetail_term;
    @Wire
    Label carddetail_wordtype;
    @Wire
    Label carddetail_phonetic;
    @Wire
    Label carddetail_definition;
    @Wire
    Label carddetail_english;
    @Wire
    Image carddetail_img;
    @Wire
    Label carddetail_notes;
    @Wire
    Label carddetail_symnonym;
    @Wire
    Label carddetail_nounperson;
    @Wire
    Label carddetail_nounthing;
    @Wire
    Label carddetail_verb;
    @Wire
    Label carddetail_adjective;
    @Wire
    Label carddetail_adverb;

    private User user;
    private List<FlashcardSet> flashcardsets = new ArrayList<FlashcardSet>();

    private Flashcard flashcard;

    public Flashcard getFlashcard() {
        return flashcard;
    }

    public void setFlashcard(Flashcard flashcard) {
        this.flashcard = flashcard;
    }

    public List<Checkbox> getLchkFlashcards() {
        if (lchkFlashcards == null) {
            lchkFlashcards = new ArrayList<Checkbox>();
        }
        return lchkFlashcards;
    }

    public void setLchkFlashcards(List<Checkbox> lchkFlashcards) {
        this.lchkFlashcards = lchkFlashcards;
    }

    public ListModelList<Flashcard> getFlashcards() {
        return new ListModelList<Flashcard>(flashcardset.getFlashcards());
    }

    public Listbox getLListboxFlashcard() {
        return lListboxFlashcard;
    }

    public void setLListboxFlashcard(Listbox lListboxFlashcard) {
        this.lListboxFlashcard = lListboxFlashcard;
    }

    @Override
    public void doBeforeComposeChildren(Component comp) throws Exception {
        super.doBeforeComposeChildren(comp);
        Component com = Path.getComponent("//page_wordlist_detail/wordlist_detail_main");
        ctrl = (WordlistDetailMainCtrl) com.getAttribute("$composer");
        flashcardset = ctrl.getFlashcardset();
        FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
        user = Utility.getUser();
        if (!isOwner() && Utility.isLogin()) {
            setFlashcardsets(srv.getFlashcardsetsOfCurrUser(getUser(), true));
        }
        canEdit = ctrl.isAllowedEdit();
        isAdmin = flashcardset.getAdmin() != FlashcardSet.ADMIN_NO;
        setBuy(flashcardset.getAdmin() == FlashcardSet.ADMIN_BUY || flashcardset.getAdmin() == FlashcardSet.ADMIN_YES);

    };

    @Listen("onSelect=#lListboxFlashcard")
    public void onFlashcardSelect() throws IOException {
        flashcard = lListboxFlashcard.getSelectedItem().getValue();
        Clients.scrollIntoView(lListboxFlashcard.getSelectedItem());
        updateSelectedFlashcard();
        if (flashcard_name != null) {
            flashcard_name.setValue(flashcard.getTerm());
        }
    }

    /**
     * Display selected cards to the screen
     * @throws IOException
     */
    private void updateSelectedFlashcard() throws IOException {
        if (flashcard != null) {
            flashcard_term.setValue(flashcard.getTerm());
            flashcard_category.setValue(flashcard.getCategory());
            flashcard_wordtype.setValue(flashcard.getWordtype());
            flashcard_phonetic.setValue(flashcard.getPhonetic());
            flashcard_notes.setValue(flashcard.getNotes());
            flashcard_symnonym.setValue(flashcard.getSymnonym());
            // update tags
            Set<String> tags = new HashSet<String>();
            for (Tag tag : flashcardset.getTags()) {
                tags.add(tag.getName());
            }
            flashcard_tags.setValue(StringFns.join(tags.toArray(), ", "));

            // sound
            soundFront.setValue(flashcard.getSoundFront());
            soundBack.setValue(flashcard.getSoundBack());
            if (StringUtils.isNotBlank(flashcard.getDefinition())) {
                flashcard_definition.setVisible(true);
                flashcard_definition.setValue(flashcard.getDefinition());
            } else {
                flashcard_definition.setVisible(false);
            }
            flashcard_img.setVisible(StringUtils.isNotBlank(flashcard.getImage()));
            flashcard_img.setSrc(Utility.loadImageFromGridFS(flashcard.getImage(), ""));

            Clients.evalJavaScript("$.updateCardShowcaseLayout(" + String.valueOf(Utility.isLogin() ? 1 : 0) + ")");

            // update card detail
            cardid.setValue(flashcard.getId().toString());
            carddetail_term.setValue(flashcard.getTerm());
            carddetail_wordtype.setValue(flashcard.getWordtype());
            carddetail_phonetic.setValue(flashcard.getPhonetic());
            carddetail_definition.setValue(flashcard.getDefinition());
            carddetail_english.setValue(flashcard.getEnglish());
            if (StringUtils.isNotBlank(flashcard.getImage())) {
                carddetail_img.setVisible(true);
                carddetail_img.setSrc(Utility.loadImageFromGridFS(flashcard.getImage(), ""));
            }
            carddetail_notes.setValue(flashcard.getNotes());
            carddetail_symnonym.setValue(flashcard.getSymnonym());
            carddetail_nounperson.setValue(flashcard.getNounperson());
            carddetail_nounthing.setValue(flashcard.getNounthing());
            carddetail_verb.setValue(flashcard.getVerb());
            carddetail_adjective.setValue(flashcard.getAdjective());
            carddetail_adverb.setValue(flashcard.getAdverb());
            Clients.evalJavaScript("$.updateCardDetailLayout()");
        }
    }

    @Listen("onClick=#delFlashcardsSelected")
    public void deleteFlashcardsSelected() {
        if (isOwner()) {
            FlashcardService fSrv = Repository.getInstance().getFlashcardService();
            FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();

            int count = 0;
            for (Checkbox chk : lchkFlashcards) {
                if (chk.isChecked()) {
                    Flashcard fc = flashcardset.getFlashcardById((Long) chk.getValue());
                    flashcardset.removeFlashcard(fc);
                    fSrv.delete(fc);
                    count++;
                }
            }

            if (count > 0) {
                fsSrv.save(flashcardset);
                ctrl.list_flashcards.invalidate();
                ctrl.grid_flashcards.invalidate();
            } else {
                Clients.evalJavaScript("showNotice('','Bạn chưa chọn flashcard')");
            }
        }
    }

    @Listen("onClick=#editFlashcard")
    public void editFlashcard() throws IOException {
        if (flashcard != null) {
            Utility.redirect(Utility.removeContextPath(Utility.generateUrl("editflashcardset", flashcardset.getId(), "fcids=" + flashcard.getId())),
                    true);
        } else {
            Clients.evalJavaScript("showNotice('','Bạn hãy chọn một flashcard để chỉnh sửa');");
        }
    }

    @Listen("onClick=#delFlashcard")
    public void deleteFlashcard() {
        if (flashcard != null && isOwner()) {
            FlashcardService fSrv = Repository.getInstance().getFlashcardService();
            FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
            flashcardset.removeFlashcard(flashcard);
            fSrv.delete(flashcard);
            fsSrv.save(flashcardset);

            ctrl.list_flashcards.invalidate();
            ctrl.grid_flashcards.invalidate();
        }
    }

    // save current flashcard set into your wordlist
    @Listen("onClick=#save_set")
    public void saveSet() {
        FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();

        fsSrv.saveSetIntoSet(flashcardset);
    }

    @Listen("onChanging=#fTerm")
    public void doChange(InputEvent event) {
        Map<String, Object> args = new HashMap<String, Object>();
        args.put("term", event.getValue());
        args.put("flashcardset", flashcardset);
        BindUtils.postGlobalCommand(null, null, "doChange", args);
    }

    /**
     * edit flashcards selected
     * Created by: Nguyen Trung Tam
     * Created date: 09/11/12
     */
    @Listen("onClick=#editSelected")
    public void doEditSelected() {
        if (isOwner()) {
            String ids = "";
            for (Checkbox chk : lchkFlashcards) {
                if (chk.isChecked()) {
                    Long id = chk.getValue();
                    ids += String.valueOf(id) + ",";
                }
            }
            if (ids.length() > 0) {
                ids = StringFns.substring(ids, 0, ids.length() - 1);
                Utility.redirect(Utility.removeContextPath(Utility.generateUrl("editflashcardset", flashcardset.getId(), "fcids=" + ids)), true);
            } else {
                Clients.evalJavaScript("showNotice('', 'Bạn hãy chọn flashcard để chỉnh sửa')");
            }
        }
    }

    @Listen("onClick=#l_list")
    public void doDisplayList() {
        ctrl.listOrGrid(true);
    }

    @Listen("onClick=#l_grid")
    public void doDisplayGrid() {
        ctrl.listOrGrid(false);
    }

    public boolean isOwner() {
        User user = Utility.getUser();
        try {
            return user.getId().equals(flashcardset.getAuthor().getId());
        } catch (Exception e) {
            return false;
        }
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<FlashcardSet> getFlashcardsets() {
        return flashcardsets;
    }

    public void setFlashcardsets(List<FlashcardSet> flashcardsets) {
        this.flashcardsets = flashcardsets;
    }

    @Wire(".lchkFlashcards")
    private List<Checkbox> chkFlashcards;

    /**
     * Copy all flashcards to existing flashcardset
     */
    @Listen("onClick=#g_save_flashcards_into_set")
    public void saveIntoFlashcardSet() {
        FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
        Listitem sl = g_list_set.getSelectedItem();
        FlashcardSet setSelected = (FlashcardSet) (sl == null ? null : sl.getValue());
        if (setSelected == null) {
            Clients.evalJavaScript("showNotice('','Vui lòng chọn một flashcard set!')");
            return;
        }

        List<Long> ids = new ArrayList<Long>();
        for (Checkbox ck : chkFlashcards) {
            if (ck.isChecked()) {
                ids.add((Long) ck.getValue());
            }
        }

        if (ids.size() == 0) {
            Clients.evalJavaScript("showNotice('','Vui lòng chọn một flashcard!')");
            return;
        }

        List<String> dupplicated = new ArrayList<String>();// Dupplicated term
        int success = 0;
        for (Long id : ids) {
            Flashcard fc = flashcardset.getFlashcardById(id);
            if (setSelected.isTermExist(fc.getTerm())) {
                dupplicated.add(fc.getTerm());
                continue;
            }

            Flashcard insertFlashcard = fc.clone();
            setSelected.addFlashcard(insertFlashcard);
            success += 1;
        }
        if (success > 0) {
            // TODO Check blank flashcard
            fsSrv.save(setSelected);
        }
        String fail = StringFns.join(dupplicated.toArray(), ", ");
        if (fail.length() > 0) {
            Clients.evalJavaScript("showNotice('', 'Hoàn tất! Các card sau bị trùng: " + fail + "')");
        } else if (success > 0) {
            Clients.evalJavaScript("showNotice('', 'Hoàn tất!')");
        }
    }

    @Listen("onClick=#g_create_set")
    public void createAndSaveFlashcardSet() {
        FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
        if (Utility.isEmptyString(g_name_set.getValue())) {
            Clients.evalJavaScript("showNotice('','Vui lòng nhập tên flashcard set');");
            return;
        }
        List<Long> ids = new ArrayList<Long>();
        for (Checkbox ck : chkFlashcards) {
            if (ck.isChecked()) {
                ids.add((Long) ck.getValue());
            }
        }

        if (ids.size() == 0) {
            Clients.evalJavaScript("showNotice('','Vui lòng chọn một flashcard!')");
            return;
        }

        FlashcardSet newSet = new FlashcardSet();
        newSet.setName(g_name_set.getValue());
        newSet.setAuthor(user);
        newSet.setDescription(description_set.getValue());
        if (!Utility.isEmptyString(tags_set.getValue())) {
            newSet.addTags(Arrays.asList(tags_set.getValue().split(",")));
        }
        fsSrv.copyFlashcards(flashcardset, ids, newSet);
        fsSrv.save(newSet);

        Executions.sendRedirect("/flashcard.zul?task=edit&id=" + newSet.getId().toString());
    }

    public List<Checkbox> getChkFlashcards() {
        return chkFlashcards;
    }

    public void setChkFlashcards(List<Checkbox> chkFlashcards) {
        this.chkFlashcards = chkFlashcards;
    }

    /**
     * @return the canEdit
     */
    public boolean isCanEdit() {
        return canEdit;
    }

    /**
     * @param canEdit the canEdit to set
     */
    public void setCanEdit(boolean canEdit) {
        this.canEdit = canEdit;
    }

    /**
     * @return the isAdmin
     */
    public boolean isAdmin() {
        return isAdmin;
    }

    /**
     * @param isAdmin the isAdmin to set
     */
    public void setAdmin(boolean isAdmin) {
        this.isAdmin = isAdmin;
    }

    public boolean isBuy() {
        return buy;
    }

    public void setBuy(boolean buy) {
        this.buy = buy;
    }
}
